#pragma once
#include "effect.h"
#include <string>
#include "matrix.h"
#include "vector3.h"
#include "vector2.h"
#include "refc_ptr.h"
#include "shader_catalog.h"

namespace krryn{
namespace view{
	enum shader_error_type{
		shader_compile_error,
		shader_parameter_error,
		shader_warning,
	};

	class shader_error{
	public:
		shader_error(const std::string &a_Error, shader_error_type a_Type) : m_Error(a_Error), m_Type(a_Type) {}

		std::string m_Error;
		shader_error_type m_Type;
	};

	class texture;
	class render_target;

	class shader : public effect{
	public:
		shader(shader_catalog &a_Catalog) : m_Catalog(a_Catalog) {}

		virtual ~shader() {}

		virtual void bind_texture2d(shader_type a_Type, const std::string &a_Name, view::texture *a_Texture) = 0;

		// This function exposes the render buffers of the render targets as uniform samplers to the shader
		// Eg. you can use them as input for you shader this way.
		virtual void bind_textures_of_render_target(shader_type a_Type, krryn::core::refc_ptr<render_target> a_Targets) = 0;

		virtual void bind_matrix4x4(shader_type a_Type, const std::string &a_Name, const math::matrix &a_Matrix) = 0;
		virtual void bind_float4(shader_type a_Type, const std::string &a_Name, math::vector4f a_Vector) = 0;
		virtual void bind_float3(shader_type a_Type, const std::string &a_Name, math::vector3f a_Vector) = 0;
		virtual void bind_float2(shader_type a_Type, const std::string &a_Name, math::uv a_Vector) = 0;
		virtual void bind_float(shader_type a_Type, const std::string &a_Name, float a_Scalar) = 0;

		virtual void bind_matrix4x4_array(shader_type a_Type, const std::string &a_Name, int a_Count, math::matrix *a_Matrix) = 0;
		virtual void bind_float4_array(shader_type a_Type, const std::string &a_Name, int a_Count, math::vector4f *a_Vector) = 0;
		virtual void bind_float3_array(shader_type a_Type, const std::string &a_Name, int a_Count, math::vector3f *a_Vector) = 0;
		virtual void bind_float2_array(shader_type a_Type, const std::string &a_Name, int a_Count, math::uv *a_Vector) = 0;
		virtual void bind_float_array(shader_type a_Type, const std::string &a_Name, int a_Count, float *a_Scalar) = 0;

		virtual std::string get_source(shader_type a_Type) = 0;
		virtual std::string get_compiled_source(shader_type a_Type) = 0;

		virtual void enable() = 0;
		virtual void disable() = 0;
	protected:
		shader_catalog &m_Catalog;
	};
}
}